package uml2Java;

import java.util.Collection;
import java.util.Map;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Type;

import astjava.BodyDeclaration;
import astjava.ClassDeclaration;
import astjava.JavaFactory;
import astjava.MethodDeclaration;
import astjava.Modifier;
import astjava.SingleVariableDeclaration;
import astjava.TypeAccess;

public class TransformAssociations {

	private Package _umlPackage; 
	
	private Map<String, astjava.Type> _symbolMap;

	public TransformAssociations(TransformPackagesAndTypes transformerTypes) {
		_umlPackage = transformerTypes.get_umlPackage();
		_symbolMap = transformerTypes.get_symbolMap();
	}

	public void doTransformAssociation() {
		for (Type umlType : _umlPackage.getOwnedTypes()) {
			if (umlType instanceof Association) {
				Association umlAssociation = (Association) umlType;
				Property role0 = umlAssociation.getOwnedEnds().get(0);
				Property role1 = umlAssociation.getOwnedEnds().get(1);
				if (role0.isNavigable()) {
					ClassDeclaration javaClass =  (ClassDeclaration) _symbolMap.get(role1.getType().getName());
					Collection<BodyDeclaration> resultat = generateAssociationAccessors(role0);
					for (BodyDeclaration bd : resultat) {
						javaClass.getBodyDeclarations().add(bd);
					}
				}
				if (role1.isNavigable()) {
					ClassDeclaration javaClass =  (ClassDeclaration) _symbolMap.get(role0.getType().getName());
					Collection<BodyDeclaration> resultat = generateAssociationAccessors(role1);
					for (BodyDeclaration bd : resultat) {
						javaClass.getBodyDeclarations().add(bd);
					}
				}
			}
		}
	}

	private Collection<BodyDeclaration> generateAssociationAccessors(Property role) {
		Collection<BodyDeclaration> result = new BasicEList<BodyDeclaration>();
		if (role.getUpper() == 1) {
			result.add(generateGetterOnAssociation(role));
			result.add(generateSetterOnAssociation(role));
		}
		else 
			result.add(generateGetterOnNotUnaryAssociation(role));
		return result;
	}
	
	private MethodDeclaration generateGetterOnNotUnaryAssociation(Property umlProperty) {
		MethodDeclaration getter = JavaFactory.eINSTANCE.createMethodDeclaration();
		getter.setName("get_"+umlProperty.getName());
		getter.setReturnType(JavaFactory.eINSTANCE.createTypeAccess());
		getter.getReturnType().setType(_symbolMap.get("Collection"));
		TypeAccess p = JavaFactory.eINSTANCE.createTypeAccess();
		p.setType(_symbolMap.get(umlProperty.getType().getName()));
		getter.getReturnType().setQualifier(p);
		setPublicModifier(getter);
		return getter;
	}
	
	private MethodDeclaration generateGetterOnAssociation(Property umlProperty) {
		MethodDeclaration getter = JavaFactory.eINSTANCE.createMethodDeclaration();
		getter.setName("get_"+umlProperty.getName());
		getter.setReturnType(JavaFactory.eINSTANCE.createTypeAccess());
		getter.getReturnType().setType(_symbolMap.get(umlProperty.getType().getName()));
		setPublicModifier(getter);
		return getter;
	}
	
	

	private BodyDeclaration generateSetterOnAssociation(Property umlProperty) {
		MethodDeclaration setter = JavaFactory.eINSTANCE.createMethodDeclaration();
		setter.setName("set_"+umlProperty.getName());
		setter.setReturnType(JavaFactory.eINSTANCE.createTypeAccess());
		setter.getReturnType().setType(_symbolMap.get("EVoid"));
		SingleVariableDeclaration parametre = JavaFactory.eINSTANCE.createSingleVariableDeclaration();
		parametre.setName(umlProperty.getName());
		parametre.setType(JavaFactory.eINSTANCE.createTypeAccess());
		parametre.getType().setType(_symbolMap.get(umlProperty.getType().getName()));
		setPublicModifier(setter);
		setter.getParameters().add(parametre);
		return setter;
	}
	
	private void setPublicModifier(MethodDeclaration method) {
		Modifier modifier = JavaFactory.eINSTANCE.createModifier();
		modifier.setVisibility(astjava.VisibilityKind.PUBLIC);
		method.setModifier(modifier);
	}

}
